﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using Thor.Configuration;
using Thor.Domain;
using Thor.Domain.Configuration;

namespace Thor.Domain
{
    public class CalendarMonitorHelper
    {
        #region fields

        private static ConfigurationSettings _ConfigSettings = new ConfigurationSettings();
        private static int _interval = Convert.ToInt32(ConfigurationSettings.CalendarMonitorInterval);
        private static List<CalendarMonitor> _monitors = new List<CalendarMonitor>();
        private static object _lockObject = new Object();

        #endregion

        #region constructors

        private CalendarMonitorHelper() { }

        #endregion

        #region properties

        private static ConfigurationSettings ConfigurationSettings
        {
            get
            {
                if (_ConfigSettings == null)
                    _ConfigSettings = new ConfigurationSettings();

                return _ConfigSettings;
            }
        }

        public static bool IsRunning { get; internal set; }

        #endregion

        #region methods

        /// <summary>
        /// Starts monitoring calendars.
        /// </summary>
        public static void StartMonitors()
        {
            if (!IsRunning)
            {
                var settings = SettingsHelper.GetSettings();
                var provider = CalendarProviderHelper.GetCalendarProvider(settings.AssemblyName, settings.AssemblyType);
                var calendars = CalendarHelper.GetCalendars();

                _monitors = new List<CalendarMonitor>();

                foreach (var calendar in calendars)
                {
                    var monitor = CalendarMonitorHelper.GetCalendarMonitor(settings, provider, calendar);
                    _monitors.Add(monitor);

                    monitor.CalendarChanged += new CalendarChangedEventHandler(Monitor_CalendarChanged);
                    monitor.Start();
                }

                IsRunning = true;
            }
        }

        /// <summary>
        /// Stops monitoring calendars.
        /// </summary>
        public static void StopMonitors()
        {
            if (IsRunning)
            {
                if (_monitors != null && _monitors.Count > 0)
                {
                    foreach (var monitor in _monitors)
                    {
                        monitor.Stop();
                    }
                }

                IsRunning = false;
            }
        }

        /// <summary>
        /// Restarts calendar monitoring.
        /// </summary>
        public static void RestartMonitors()
        {
            if (IsRunning)
            {
                StopMonitors();
                //TODO: wait until all monitors are stopped

                StartMonitors();
                //TODO: wait until all monitors are started

            }
        }

        /// <summary>
        /// Gets the monitor for a specific calendar.
        /// </summary>
        /// <param name="settings">Settings to use for monitor.</param>
        /// <param name="provider">Provider to use for monitor.</param>
        /// <param name="calendar">Calendar to monitor.</param>
        /// <returns></returns>
        private static CalendarMonitor GetCalendarMonitor(Settings settings, CalendarProviderBase provider, Calendar calendar)
        {
            CalendarMonitorParameters parameters = new CalendarMonitorParameters();
            parameters.Request = GetCalendarRequest(settings, calendar);
            parameters.Provider = provider;
            parameters.Interval = _interval;
            parameters.LoadOnStart = true;
            parameters.Calendar = calendar;

            return new CalendarMonitor(parameters);
        }

        /// <summary>
        /// Gets a calendar request.
        /// </summary>
        /// <param name="settings">Settings to use to generate the request.</param>
        /// <param name="calendar">Calendar to generate the request for.</param>
        /// <returns></returns>
        private static CalendarRequest GetCalendarRequest(Settings settings, Calendar calendar)
        {
            string serviceUrl = settings.CalendarProviderUri;
            string calendarId = calendar.CalendarEmail;

            CalendarRequest request = new CalendarRequest()
            {
                CalendarId = calendarId,
                Credential = SettingsHelper.GetNetworkCredential(),
                EndDate = null,
                ServiceUrl = serviceUrl,
                StartDate = null,
                Alias = calendar.Alias
            };

            return request;
        }

        private static void Monitor_CalendarChanged(object sender, CalendarChangedEventArgs e)
        {
            lock (_lockObject)
            {
                CalendarHelper.SaveCalendar(e.Calendar);
            }
        }

        #endregion
    }
}
